﻿using Infrastructure.Extensions;
using Infrastructure.Model;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace Infrastructure.Helper
{
    public class JwtUtil
    {
        // JWT 加密密钥
        public static readonly string KEY = "julianchongmanchun";

        /// <summary>
        /// 从 HttpContext 和分布式缓存中获取登录用户信息
        /// </summary>
        /// <param name="httpContext">HttpContext 对象</param>
        /// <param name="distributedCache">分布式缓存对象</param>
        /// <returns>登录用户信息，如果未找到有效的 Token 则返回 null</returns>
        public static LoginUser GetLoginUser(HttpContext httpContext, IDistributedCache distributedCache)
        {
            // 从 HttpContext 中获取 Token
            string token = httpContext.GetToken(distributedCache);
            if (!string.IsNullOrEmpty(token))
            {
                // 验证并解析 Token，返回登录用户信息
                LoginUser loginUser = ValidateJwtToken(ParseToken(token));
                loginUser.Token = token;
                return loginUser;
            }

            return null;
        }

        /// <summary>
        /// 生成 JWT Token
        /// </summary>
        /// <param name="claims">要包含在 Token 中的 Claims</param>
        /// <returns>生成的 JWT Token 字符串</returns>
        public static string GenerateJwtToken(List<Claim> claims)
        {
            JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
            byte[] bytes = Encoding.ASCII.GetBytes(KEY);
            SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(claims),
                Expires = DateTime.Now.AddYears(1),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(bytes), SecurityAlgorithms.HmacSha256Signature)
            };
            SecurityToken token = jwtSecurityTokenHandler.CreateToken(tokenDescriptor);
            return jwtSecurityTokenHandler.WriteToken(token);
        }

        /// <summary>
        /// 解析 JWT Token
        /// </summary>
        /// <param name="token">要解析的 JWT Token 字符串</param>
        /// <returns>解析后的 Claims 集合，如果解析失败则返回 null</returns>
        public static IEnumerable<Claim> ParseToken(string token)
        {
            JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
            byte[] bytes = Encoding.ASCII.GetBytes(KEY);
            try
            {
                jwtSecurityTokenHandler.ValidateToken(token, new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(bytes),
                    ValidateIssuer = false,
                    ValidateAudience = false,
                    ClockSkew = TimeSpan.Zero
                }, out var validatedToken);
                JwtSecurityToken jwtSecurityToken = (JwtSecurityToken)validatedToken;
                return jwtSecurityToken.Claims;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return null;
            }
        }

        /// <summary>
        /// 验证 JWT Token 并返回登录用户信息
        /// </summary>
        /// <param name="jwtToken">JWT Token 中的 Claims</param>
        /// <returns>登录用户信息，如果验证失败则返回 null</returns>
        private static LoginUser ValidateJwtToken(IEnumerable<Claim> jwtToken)
        {
            try
            {
                // 根据 Token 中的特定 Claim 类型解析出用户信息
                string value = jwtToken.FirstOrDefault((Claim x) => x.Type == "primarysid")?.Value;
                string value2 = jwtToken.FirstOrDefault((Claim x) => x.Type == "unique_name")?.Value;
                string value3 = jwtToken.FirstOrDefault((Claim x) => x.Type == "http://schemas.microsoft.com/ws/2008/06/identity/claims/userdata")?.Value;
                return JsonConvert.DeserializeObject<LoginUser>(value3);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return null;
            }
        }
    }

}
